﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ThouShaltNotBrick.Models;
using System.IO;
using GMUtilitiesDotNet.Helpers;
using ThouShaltNotBrick.DataAccess;
using ThouShaltNotBrickLevelEditor.Models;
using ThouShaltNotBrickLevelEditor.DataAccess;
using ThouShaltNotBrickLevelEditor.Code.GeneralObjects;
using ThouShaltNotBrickLevelEditor.Code.Helpers;

namespace ThouShaltNotBrickLevelEditor.Code.Managers
{
    public sealed class LevelManager
    {
        #region Constants
        private const string BRICK_STATES_FILE_PATH = "BrickStates.brickstates";
        private const string BRICK_TYPES_FILE_PATH = "BrickTypes.bricktypes";
        private const string BRICK_STATE_IMAGES_FOLDER_PATH = @"BrickStates\";
        #endregion

        #region Properties
        #region BrickStatesTypesImages
        private BrickStatesTypesImages mBrickStatesTypesImages;

        /// <summary>
        /// BrickStatesTypesImages property.
        /// </summary>
        public BrickStatesTypesImages BrickStatesTypesImages
        {
            get
            {
                if (mBrickStatesTypesImages == null && DataFolderPath != null)
                {
                    string brickStatesFilePath = Path.Combine(DataFolderPath, BRICK_STATES_FILE_PATH);
                    BrickStatesData brickStatesData = BrickStatesXmlReader.Read(brickStatesFilePath);

                    string brickTypesFilePath = Path.Combine(DataFolderPath, BRICK_TYPES_FILE_PATH);
                    BrickTypesData brickTypesData = BrickTypesXmlReader.Read(brickTypesFilePath);

                    string brickStateImagesFolderPath = Path.Combine(DataFolderPath, BRICK_STATE_IMAGES_FOLDER_PATH);
                    BrickStateImages brickStateImages = BrickStateImagesLoader.Load(brickStateImagesFolderPath);

                    mBrickStatesTypesImages = new BrickStatesTypesImages(
                        brickStatesData,
                        brickTypesData,
                        brickStateImages);
                }
                return mBrickStatesTypesImages;
            }
        }
        #endregion

        #region DataFolderPath
        private string mDataFolderPath;

        /// <summary>
        /// DataFolderPath property.
        /// </summary>
        public string DataFolderPath
        {
            get { return mDataFolderPath; }
            private set
            {
                mDataFolderPath = value;
                mBrickStatesTypesImages = null;
                RaiseBrickStatesTypesImagesChangedEvent();
            }
        }
        #endregion

        #region LevelData
        private LevelData mLevelData;

        /// <summary>
        /// LevelData property.
        /// </summary>
        public LevelData LevelData
        {
            get { return mLevelData; }
            private set
            {
                if (mLevelData != value)
                {
                    mLevelData = value;
                    IsPendingLevelChanges = true;
                    RaiseLevelDataChangedEvent();
                }
            }
        }
        #endregion

        #region LevelFilePath
        private string mLevelFilePath;

        /// <summary>
        /// LevelFilePath property.
        /// </summary>
        public string LevelFilePath
        {
            get { return mLevelFilePath; }
            private set
            {
                mLevelFilePath = value;
                LevelData = LoadLevelDataFromFile(mLevelFilePath);
                IsPendingLevelChanges = false;
            }
        }
        #endregion

        #region IsPendingLevelChanges
        /// <summary>
        /// IsPendingLevelChanges property.
        /// </summary>
        public bool IsPendingLevelChanges { get; private set; }
        #endregion

        #region BrickStateSelection
        private BrickStateSelection mBrickStateSelection;

        /// <summary>
        /// BrickStateSelection property.
        /// </summary>
        public BrickStateSelection BrickStateSelection
        {
            get { return mBrickStateSelection; }
            private set
            {
                if (mBrickStateSelection != value)
                {
                    mBrickStateSelection = value;
                    RaiseBrickStateSelectionChangedEvent();
                }
            }
        }
        #endregion
        #endregion

        #region Events
        #region BrickStatesTypesImagesChanged
        public event EventHandler BrickStatesTypesImagesChanged;
        private void RaiseBrickStatesTypesImagesChangedEvent()
        {
            var handler = BrickStatesTypesImagesChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
        #endregion

        #region LevelDataChanged
        public event EventHandler LevelDataChanged;
        private void RaiseLevelDataChangedEvent()
        {
            var handler = LevelDataChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
        #endregion

        #region BrickStateSelectionChanged
        public event EventHandler BrickStateSelectionChanged;
        private void RaiseBrickStateSelectionChangedEvent()
        {
            var handler = BrickStateSelectionChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
        #endregion
        #endregion

        #region Constructors
        public LevelManager()
        {
            DataFolderPath = null;
            LevelFilePath = null;
        }
        #endregion

        #region Methods
        public void LoadData(string pDataFolderPath)
        {
            DataFolderPath = pDataFolderPath;
        }

        public void LoadLevel(string pLevelFilePath)
        {
            if (!CanLoadLevel())
            {
                return;
            }

            LevelFilePath = pLevelFilePath;
        }

        public bool CanLoadLevel()
        {
            return BrickStatesTypesImages != null;
        }

        public void SaveLevel()
        {
            if (!CanSaveLevel())
            {
                return;
            }

            SaveLevelAs(LevelFilePath);
        }

        public bool CanSaveLevel()
        {
            return LevelData != null && BrickStatesTypesImages != null && !string.IsNullOrEmpty(LevelFilePath);
        }

        public void SaveLevelAs(string pLevelFilePath)
        {
            if (!CanSaveLevelAs())
            {
                return;
            }

            LevelData = LevelDataModifier.PrepareLevelForWrite(LevelData, pLevelFilePath);
            LevelXmlWriter.Write(pLevelFilePath, LevelData);
            IsPendingLevelChanges = false;
        }

        public bool CanSaveLevelAs()
        {
            return LevelData != null && BrickStatesTypesImages != null;
        }

        public void AddBrick(BrickPosition pBrickPosition)
        {
            if (!CanAddBrick())
            {
                return;
            }

            BrickData brickData = new BrickData(
                BrickStateSelection.BrickTypeName,
                pBrickPosition.Row,
                pBrickPosition.Column,
                BrickStateSelection.BrickStateIndex);

            LevelData = LevelDataModifier.AddBrick(LevelData, brickData);
        }

        public bool CanAddBrick()
        {
            return BrickStatesTypesImages != null && BrickStateSelection != null && LevelData != null;
        }

        public void DeleteBrick(BrickPosition pBrickPosition)
        {
            if (!CanDeleteBrick())
            {
                return;
            }

            LevelData = LevelDataModifier.DeleteBrick(LevelData, pBrickPosition);
        }

        public bool CanDeleteBrick()
        {
            return BrickStatesTypesImages != null && LevelData != null;
        }

        public void SelectBrickState(BrickStateSelection pBrickStateSelection)
        {
            if (!CanSelectBrickState())
            {
                return;
            }

            BrickStateSelection = pBrickStateSelection;
        }

        public bool CanSelectBrickState()
        {
            return BrickStatesTypesImages != null;
        }

        private static LevelData LoadLevelDataFromFile(string pLevelFilePath)
        {
            if (string.IsNullOrEmpty(pLevelFilePath))
            {
                return LevelDataModifier.CreateEmptyLevelData();
            }

            return LevelXmlReader.Read(pLevelFilePath);
        }
        #endregion
    }
}